//
//  GoEasy.swift
//  uwantgoeasy
//
//  Created by 冯传宝 on 12/11/15.
//  Copyright © 2015 uwantsoft. All rights reserved.
//

import Foundation

public class GoEasy {
    
    private final let server:String = "192.168.31.218"
//    private final let server:String = "test.goeasy.io"
    private final let port:UInt16 = 8000
    
    private var socketClient: UwantSocketClient?
    private var clientListener:ClientListener?
    
    private var sid: String=""
    private var appkey: String=""
    private var userId: String=""
    private var username: String=""
    private var startSeconds: Double = NSDate.timeIntervalSinceReferenceDate()
    private var connectDurationMillis:UInt=0
    private var subscribeListeners:Dictionary=Dictionary<String,SubscribeListener>()
    private var publishes:Dictionary<String,PublishMessage>=Dictionary<String,PublishMessage>()
    private var unsubscribeListeners:Dictionary<String,UnsubscribeListener>=Dictionary<String,UnsubscribeListener>()
    private var authorizeResult: AuthorizeResult = AuthorizeResult()
    private static var subscribe_timeout:Double = 12.0
    public init(appkey: String){
        clientListener = ClientListener(goEasy:self)
        socketClient = UwantSocketClient.shareInstance(server, port: port)
        let defaults = NSUserDefaults.standardUserDefaults()
        if let sid = defaults.stringForKey("sid"){
            print("goeasy sid:\(self.sid)")
            print("preference sid:\(sid)")
            self.sid = sid
        }
        socketClient!._socketClientListener=GoEasySocketClientListener(goEasy: self)
        self.appkey = appkey
    }
    
    convenience public init(appkey:String, clientListener:ClientListener){
        self.init(appkey:appkey)
        self.clientListener = clientListener
    }
    
    convenience public init(appkey:String, username:String, userId:String){
        self.init(appkey:appkey);
        self.username = username
        self.userId = userId
    }
    convenience public init(appkey:String, username:String, userId:String,clientListener:ClientListener){
        self.init(appkey:appkey,clientListener:clientListener);
        self.username = username
        self.userId = userId
    }
    
    func login(){
        print("will login..")
        let authenticationToken = AuthenticationToken(sid: self.sid, appkey: self.appkey, userId: friendlyUserId(), username: self.username, connectDurationMills: self.connectDurationMillis)
        socketClient?.messageSender!.send(authenticationToken)
    }
    
    public func subscribe(channel:String,subscribeListener:SubscribeListener){
        confirmAuthorizeResult()
        subscribeListener.setGoEasy(self)
        subscribeListeners.updateValue(subscribeListener, forKey: channel)
        switch(authorizeResult._resultCode){
        case MessageCode.OK.rawValue:
            if(authorizeResult._enableSubscribe){
                let subscribe:Subscribe = Subscribe(sid:self.sid,channel:channel)
                socketClient!.messageSender?.send(subscribe)
            }else{
                subscribeListener.onFailed(GoEasyError(code: 401, content: "Unauthorized"))
            }
        case MessageCode.TIMEOUT.rawValue:
            subscribeListener.onFailed(GoEasyError(code: 408,content: "Unreachable or timeout"))
        default:
            print("Unhandled message code:\(authorizeResult._resultCode)")
        }
    }
    private func confirmAuthorizeResult(){
        let start = NSDate.timeIntervalSinceReferenceDate()
        while(self.authorizeResult._resultCode == 0){
            let now = NSDate.timeIntervalSinceReferenceDate()
            if(now - start > GoEasy.subscribe_timeout){
                let code = MessageCode.TIMEOUT.rawValue
                authorizeResult._resultCode=code
            }
        }
    }
    public func unsubscribe(channel: String){
        unsubscribe(channel, unsubscribeListener: UnsubscribeListener())
    }

    public func unsubscribe(channel: String, unsubscribeListener: UnsubscribeListener){
        unsubscribeListener.goeasy(self)
        unsubscribeListeners.updateValue(unsubscribeListener, forKey: channel)
        let unsubscribe = Unsubscribe(sid: sid, channel: channel)
        socketClient?.messageSender?.send(unsubscribe)
    }
    public func publish(channel:String, content:String){
        publish(channel, content: content, publishListener: PublishListener())
    }
    public func publish(channel:String, content:String, publishListener:PublishListener){
        if(authorizeResult._resultCode==0 || !authorizeResult._enablePublish){
            publishListener.onFailed(GoEasyError(code: 401, content: "Unauthorized"))
            return
        }
        let publishMessage = PublishMessage(sid: sid,channel: channel,content: content,publishListener: publishListener)
        socketClient?.messageSender?.send(publishMessage)
        publishes.updateValue(publishMessage, forKey: publishMessage._ackId)
    }
    
    func updateConnectDurationMillis(){
        let now = NSDate.timeIntervalSinceReferenceDate()
        self.connectDurationMillis=UInt((now-startSeconds)*1000)
    }
    
    func connectSuccess(authorizeResult: AuthorizeResult){
        self.sid = authorizeResult._sid
        self.authorizeResult = authorizeResult
        let defaults = NSUserDefaults.standardUserDefaults()
        defaults.setObject(sid, forKey: "sid")
        let ipUpdator = ClientIpUpdator()
        ipUpdator.update(self.sid)
    }
    
    func onPublishResult(publishResult: PublishResult){
        let publishMessage = publishes[publishResult._ackId]
        publishMessage?._publishListener.onPublishResult(publishResult)
        publishes.removeValueForKey(publishResult._ackId)
    }
    
    func onUnsubscribeSuccess(channel: String){
        unsubscribeListeners.removeValueForKey(channel)
    }
    
    func connectFailed(authorizeResult: AuthorizeResult){
        self.authorizeResult = authorizeResult
    }
    var _clientListener:ClientListener{
        get{
            return clientListener!
        }
        set(newVal){
            clientListener = newVal
            clientListener?.goEasy(self)
        }
    }
    
    var _sid:String{
        get{
            return sid
        }
    }
    
    var _socketListener:UwantSocketClient{
        get{
            return socketClient!
        }
    }
    
    func subscribeListener(channel:String) -> SubscribeListener{
        return subscribeListeners[channel]!
    }
    
    func unsubscribeListener(channel:String) -> UnsubscribeListener{
        return unsubscribeListeners[channel]!
    }
    
    private func friendlyUserId() -> String{
        if(self.userId.isEmpty){
            let annoy_num = arc4random_uniform(100000)+100000
            self.userId = "annonymous_ios_\(annoy_num)"
        }
        return self.userId;
    }
}